package service

import (
	"qld2devservice/models"
	"qld2devservice/utils"
	"strconv"
	"strings"
	"time"

	cmap "github.com/streamrail/concurrent-map"
)

const DEV_STATUS_QUEUE_LENGTH = 300000

var (
	devMap            cmap.ConcurrentMap
	recvDevStatusChan chan DevStatus
)

func GetAllDevice() error {
	makeDevStatusQueue()

	devMap = cmap.New()
	devices, err := models.GetAllQldOutletSnNumAndTypeAndStatus()

	dataList := make([]interface{}, 2*10000)
	dataListIndex := 0
	for i := 0; i < len(devices); i++ {
		devMap.Set(devices[i].SnNum, strconv.FormatInt(int64(devices[i].Type), 10))
		// if err = RedisSave(devices[i].SnNum+"/status", strconv.FormatInt(int64(devices[i].Status), 10)); err != nil {
		// 	utils.MyPrint(utils.PRINT_ERROR , utils.WrapError(err, "OutLetOpen: 4，isWorking保存到etcd失败"))
		// }
		// if err = MqttNoticeSend(devices[i].SnNum+"/status", strconv.FormatInt(int64(devices[i].Status), 10)); err != nil {
		// 	utils.MyPrint(utils.PRINT_ERROR , utils.WrapError(err, "OutLetOpen: isWorking推送失败"))
		// }
		if devices[i].Status == 0 && (devices[i].Type == 0 || devices[i].Type == 1 || devices[i].Type == 2 || devices[i].Type == 4 || devices[i].Type == 5 || devices[i].Type == 9) { //是可用的
			checkOnline(devices[i].SnNum)
		}
		dataList[dataListIndex] = "/" + appNameRedis + "/" + devices[i].SnNum + "/status"
		dataListIndex++
		dataList[dataListIndex] = strconv.FormatInt(int64(devices[i].Status), 10)
		dataListIndex++
		if dataListIndex == 20000 {
			dataListIndex = 0
			RedisMSetKeyListNoHeader(dataList)
		}
	}
	if dataListIndex > 0 {
		RedisMSetKeyListNoHeader(dataList[:dataListIndex])
	}

	go func() {
		utils.MyPrint(utils.PRINT_INFO, "开始定时任务,每30分钟一次")
		ticker := time.NewTicker(time.Minute * 30) // 每隔10分钟进行一次
		for {
			//go func() {
			//	if deviceList, err2 := models.GetAllQldOutletSnNumAndIsWorkingAndStatus(); err2 != nil {
			//		utils.MyPrint(utils.PRINT_ERROR, "GetAllQldOutletSnNumAndIsWorkingAndStatus failed, err:", err2.Error())
			//	} else {
			//		for i := 0; i < len(deviceList); i++ {
			//			if len(deviceList[i].SnNum) > 0 && (deviceList[i].Type == 0 || deviceList[i].Type == 1 || deviceList[i].Type == 2 || deviceList[i].Type == 4 || deviceList[i].Type == 5) {
			//				updateIsWorkingAndStatus(deviceList[i].SnNum, deviceList[i].IsWorking, deviceList[i].Status)
			//			}
			//		}
			//	}
			//}()
			go func() {
				// if onlineList, err := RedisKeyListNoHeader("online"); err != nil {
				// 	utils.MyPrint(utils.PRINT_ERROR , err.Error(), "GetAllDevice:redis获取online列表失败")
				// } else {
				// 	for i := 0; i < len(onlineList); i++ {
				// 		checkOnlineErr(onlineList[i])
				// 	}
				// }
				if onlineList, err := RedisKeyListNoHeader("online"); err != nil {
					utils.MyPrint(utils.PRINT_ERROR, err.Error(), "GetAllDevice:redis获取online列表失败")
				} else {
					onlineSnNumList := make(map[string]bool)
					for i := 0; i < len(onlineList); i++ {
						result := strings.Split(onlineList[i], "/")
						if len(result) > 2 {
							onlineSnNumList[result[2]] = true
						}
					}
					utils.MyPrint(utils.PRINT_INFO, "开始获取桩设备了.....=======>")
					if devices, err := models.GetAllQldOutletSnNumAndTypeAndStatus(); err != nil {
						utils.MyPrint(utils.PRINT_ERROR, err.Error(), "GetAllDevice:redis获取online列表失败")
					} else {
						for i := 0; i < len(devices); i++ {
							devMap.Set(devices[i].SnNum, strconv.FormatInt(int64(devices[i].Type), 10))
							if devices[i].Type == 0 || devices[i].Type == 1 || devices[i].Type == 2 || devices[i].Type == 4 || devices[i].Type == 5 || devices[i].Type == 9 { //是可用的
								if _, ok := onlineSnNumList[devices[i].SnNum]; ok && devices[i].Status == 2 {
									utils.MyPrint(utils.PRINT_INFO, devices[i].SnNum, "开始更新成在线状态")
									PutDevStatusChange(devices[i].SnNum, 0)
									snNum := devices[i].SnNum
									time.AfterFunc(8*time.Second, func() {

										if err = RedisSave(snNum+"/status", "0"); err != nil {
											utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败"))
										}
										if err = MqttNoticeSend(snNum+"/status", "0"); err != nil {
											utils.MyPrint(utils.PRINT_ERROR, err.Error())
										}
									})
								} else if !ok && devices[i].Status == 0 {
									utils.MyPrint(utils.PRINT_INFO, devices[i].SnNum, "开始更新成离线状态")
									PutDevStatusChange(devices[i].SnNum, 2)
									snNum := devices[i].SnNum
									time.AfterFunc(8*time.Second, func() {
										if err = RedisSave(snNum+"/status", "2"); err != nil {
											utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败"))
										}
										if err = MqttNoticeSend(snNum+"/status", "2"); err != nil {
											utils.MyPrint(utils.PRINT_ERROR, err.Error())
										}
									})
								}
							}
						}
					}
				}
			}()
			//go func() {
			//	if snNumKeyList, err := RedisKeyListNoHeader("/userId_snNum/"); err != nil {
			//		utils.MyPrint(utils.PRINT_ERROR , err.Error(), "GetAllDevice:redis获取userId_snNum列表失败")
			//	} else {
			//		for i := 0; i < len(snNumKeyList); i++ {
			//			checkUserIdsnNum(snNumKeyList[i])
			//		}
			//	}
			//}()
			<-ticker.C
		}
	}()

	return err
}

func checkOnline(snNum string) {
	time.AfterFunc(400*time.Second, func() {
		utils.MyPrint(utils.PRINT_INFO, "start check "+snNum+" online")
		if online, err := DevOnlineEtcdCheck(snNum); err != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:4,设备是否在线etcd检查获取失败"))
		} else if !online { // 已经离线，更新数据库，已离线
			if statusStr, err := RedisGet(snNum+"/status", "2"); err != nil {
				utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:1,设备是否在线etcd检查获取失败"))
			} else if statusStr == "0" { // 并且此时系统记录依旧是在线，更新
				PutDevStatusChange(snNum, 2)
				if err = RedisSave(snNum+"/status", "2"); err != nil {
					utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败"))
				}
				if err = MqttNoticeSend(snNum+"/status", "2"); err != nil {
					utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败"))
				}
			}
		}
	})
}

func updateIsWorkingAndStatus(snNum string, isWorking, status int8) {
	if operateFlag, err := RedisCheck(snNum + "/operateFlag"); err != nil {
		utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "updateIsWorkingAndStatus: redis读取operateFlag失败"))
	} else if !operateFlag {
		if err := RedisSave(snNum+"/isWorking", strconv.FormatInt(int64(isWorking), 10)); err != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "updateIsWorkingAndStatus: isWorking保存到redis失败"))
		}
		if err := MqttNoticeSend(snNum+"/isWorking", strconv.FormatInt(int64(isWorking), 10)); err != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "updateIsWorkingAndStatus: isWorking推送失败"))
		}
		if err := RedisSave(snNum+"/status", strconv.FormatInt(int64(status), 10)); err != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "updateIsWorkingAndStatus: status保存到redis失败"))
		}
		if err := MqttNoticeSend(snNum+"/status", strconv.FormatInt(int64(status), 10)); err != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "updateIsWorkingAndStatus: status推送失败"))
		}
	}
}

func checkOnlineErr(key string) {
	if expiration, err := RedisGetKeyExpirationNoHeader(key); err != nil {
		utils.MyPrint(utils.PRINT_ERROR, err.Error(), "checkOnlineErr:redis获取数据存活实际失败")
	} else if expiration < time.Duration(0) {
		if _, err2 := RedisSaveExpirationNoHeader(key, "", 300); err2 != nil {
			utils.MyPrint(utils.PRINT_ERROR, err2.Error())
		} else {
			result := strings.Split(key, "/")
			if len(result) > 1 {
				if devType, err := getDevType(result[len(result)-2]); err != nil {
					utils.MyPrint(utils.PRINT_WARN, "checkOnlineErr:设备类型获取失败,snNum=", result[len(result)-2])
				} else if devType == 0 || devType == 1 || devType == 2 || devType == 4 || devType == 5 || devType == 9 {
					checkOnline(result[len(result)-2])
				}
			}
		}
	}
}

func checkUserIdsnNum(key string) {
	result := strings.Split(key, "/")
	if len(result) > 1 {
		snNum := result[len(result)-1]
		userIdStr := result[len(result)-2]
		if userIdStrNew, err4 := RedisGet(snNum+"/userId", "0"); err4 != nil {
			utils.MyPrint(utils.PRINT_ERROR, err4, "GetAllDevice:redis获取snNum的userId失败，", snNum)
		} else if userIdStr != userIdStrNew { //删掉
			if err := RedisDelNoHeader(key); err != nil {
				utils.MyPrint(utils.PRINT_ERROR, err.Error(), "GetAllDevice:redis数据删除失败，", key)
			}
		} else if isWorkingStr, err2 := RedisGet(snNum+"/isWorking", "0"); err2 != nil {
			utils.MyPrint(utils.PRINT_ERROR, err2, "GetAllDevice:redis数据isWorking获取失败，", snNum)
		} else if isWorkingStr == "0" { //删掉
			if err := RedisDelNoHeader(key); err != nil {
				utils.MyPrint(utils.PRINT_ERROR, err.Error(), "GetAllDevice:redis数据删除失败，", key)
			}
		}
	}
}

// operateFlag 0 成功 1 失败，2~ 其它原因失败
func OperateDevice(snNum string, status int32, operateType int64, repeatNum, timeOutSecond int64) (timeOutFlag bool, operateFlag int64, err error) {
	devType, err := getDevType(snNum)
	if err != nil {
		errNew := utils.WrapError(err, "OperateDevice:设备类型获取失败")
		return false, 1, errNew
	}
	cmdSendTopic, smdRecvTopic := MakeOperateDeviceCmdTopic(snNum, devType, status)
	var cmdStr string
	cmdStr, err = MakeOperateDeviceCmdStr(snNum, devType, status, operateType)
	utils.MyPrint(utils.PRINT_INFO, "拼接cmdstr:", cmdStr, err)
	if err != nil {
		return false, 1, utils.WrapError(err, "OperateDevice:1,组命令内容失败")
	} else {
		utils.MyPrintCaller(utils.PRINT_WARN, 2, snNum, cmdSendTopic, smdRecvTopic, cmdStr)
		//fmt.Println("桩号:", snNum, "发送的主题:", cmdSendTopic, smdRecvTopic, "cmdStr:", cmdStr)
		var response string
		response, timeOutFlag, err = MqttCmdDevice(cmdSendTopic, smdRecvTopic, cmdStr, repeatNum, timeOutSecond)
		if err != nil {
			return false, 1, utils.WrapError(err, "OperateDevice:2,grpc命令控制")
		} else {
			if timeOutFlag {
				return true, 0, nil
			}
			//设备类型为5的请求_start
			//if devType == 5 {
			//	utils.MyPrint(utils.PRINT_ERROR, "主动请求")
			//	responseInfo, _, _ := MqttCmdDevice("SD/"+snNum+"/RSTS", "DS/"+snNum+"/STS", cmdStr, repeatNum, 4)
			//	utils.MyPrint(utils.PRINT_ERROR, "主动请求结果:", responseInfo)
			//}
			//设备类型为5的请求_end

			_, operateFlag, err = AnalyzeOperateDeviceCmdResponse(devType, status, response)
		}
	}
	return
}

func GetQldOutletTypeBySnNum(snNum string, userId int64) (qldOutletType, operateFlag, openType, openDuration, status int64, priceDes, errMsg string, err error) {
	qldOutlets, err := models.GetQldOutletsBySnNum(snNum)
	if err != nil {
		utils.MyPrint(utils.PRINT_ERROR, err.Error())
		return 0, 0, 0, 0, 1, "", err.Error(), utils.WrapError(err, "GetQldOutletTypeBySnNum: 1，或是设备信息失败")
	} else {
		if len(qldOutlets) == 0 {
			qldChargeCabinets, err := models.GetQldChargeCabinetsBySnNum(snNum)
			if err != nil {
				utils.MyPrint(utils.PRINT_ERROR, err.Error())
				return 0, 0, 0, 0, 1, "", err.Error(), utils.WrapError(err, "GetQldOutletTypeBySnNum: 1，或是设备信息失败")
			} else if len(qldChargeCabinets) == 0 {
				utils.MyPrint(utils.PRINT_ERROR, utils.NewError(utils.ErrorTypeStop, "GetQldOutletTypeBySnNum:2,数据库获取设备未获取到,snNum="+snNum))
				return 0, 0, 0, 0, 2, "", "设备未找到", nil
			} else if len(qldChargeCabinets) > 1 {
				utils.MyPrint(utils.PRINT_ERROR, utils.NewError(utils.ErrorTypeStop, "GetQldOutletTypeBySnNum:3,数据库获取设备获取异常，获取到多个，,snNum="+snNum))
				return 0, 0, 0, 0, 2, "", "设备编号重复", nil
			} else {
				return int64(qldChargeCabinets[0].Type), 0, 0, 0, 0, "", "", nil
			}
		} else if len(qldOutlets) > 1 {
			utils.MyPrint(utils.PRINT_ERROR, utils.NewError(utils.ErrorTypeStop, "GetQldOutletTypeBySnNum:3,数据库获取设备获取异常，获取到多个，,snNum="+snNum))
			return 0, 0, 0, 0, 2, "", "设备编号重复", nil
		} else {
			devMap.Set(qldOutlets[0].SnNum, strconv.FormatInt(int64(qldOutlets[0].Type), 10))
			if qldAmountPrice, err := models.GetQldAmountPriceById(qldOutlets[0].PriceId); err != nil {
				utils.MyPrint(utils.PRINT_ERROR, err.Error())
				return int64(qldOutlets[0].Type), 0, 0, 0, 2, "", err.Error(), utils.WrapError(err, "OutLetOpen: 11，获取设备价格失败")
			} else {
				priceDes = qldAmountPrice.Des
				if statusStr, err := RedisGet(snNum+"/status", "2"); err != nil {
					utils.MyPrint(utils.PRINT_ERROR, err.Error())
					return int64(qldOutlets[0].Type), 0, 0, 0, 1, priceDes, err.Error(), utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败")
				} else if status, err := strconv.ParseInt(statusStr, 10, 64); err != nil {
					utils.MyPrint(utils.PRINT_ERROR, err.Error())
					return int64(qldOutlets[0].Type), 0, 0, 0, 1, priceDes, err.Error(), utils.WrapError(err, "MakeOperateDeviceCmd:6,数据库etcd设备离线信息推送失败")
				} else {
					if status != int64(qldOutlets[0].Status) {
						if err = RedisSave(snNum+"/status", strconv.FormatInt(int64(qldOutlets[0].Status), 10)); err != nil {
							utils.MyPrint(utils.PRINT_ERROR, err.Error())
						}
						if err = MqttNoticeSend(snNum+"/status", strconv.FormatInt(int64(qldOutlets[0].Status), 10)); err != nil {
							utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:数据库etcd设备离线信息推送失败"))
						}
						status = int64(qldOutlets[0].Status)
					}
					if err = RedisSave(snNum+"/isWorking", strconv.FormatInt(int64(qldOutlets[0].IsWorking), 10)); err != nil {
						utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum: isWorking保存到etcd失败"))
					}
					if err = MqttNoticeSend(snNum+"/isWorking", strconv.FormatInt(int64(qldOutlets[0].IsWorking), 10)); err != nil {
						utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:isWorking推送失败"))
					}
					errMsg := CheckEmergencyStop(snNum, qldOutlets[0].Type)

					if qldOutlets[0].IsWorking == 0 {
						if qldChargerOrders, err := models.GetRunningQldChargerOrderByOutletId(int64(qldOutlets[0].Id)); err != nil {
							utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:设备订单获取失败").Error())
						} else if len(qldChargerOrders) > 0 {
							if qldChargerOrders[0].UserId == userId {
								openType, err = GetOpenType(snNum)
								openDuration, err = AnalyzeDevDurationGet(snNum + "/openTime")
								return int64(qldOutlets[0].Type), 1, openType, openDuration, status, priceDes, errMsg, nil
							} else {
								return int64(qldOutlets[0].Type), 2, 0, 0, status, priceDes, errMsg, nil
							}
						}
						if qldOutlets[0].Type == 0 || qldOutlets[0].Type == 2 || qldOutlets[0].Type == 6 || qldOutlets[0].Type == 8 {
							if connectInfo, err := RedisGet(snNum+"/connectInfo", "0"); err != nil {
								utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:设备连接信息redis获取失败"))
							} else if connectInfo == "2" {
								if err := RedisSave(snNum+"/connectInfo", "0"); err != nil { // 已连接
									utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:3,设备连接信息推redis保存失败"))
								}
								if err = MqttNoticeSend(snNum+"/connectInfo", "0"); err != nil {
									utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err, "GetQldOutletTypeBySnNum:设备连接信息推送失败"))
								}
							}
						}
						return int64(qldOutlets[0].Type), 0, 0, 0, status, priceDes, errMsg, nil
					} else if qldOutlets[0].IsWorking == 1 && qldOutlets[0].UserId == userId {
						openType, err = GetOpenType(snNum)
						openDuration, err = AnalyzeDevDurationGet(snNum + "/openTime")

						return int64(qldOutlets[0].Type), 1, openType, openDuration, status, priceDes, errMsg, nil
					} else if qldOutlets[0].IsWorking == 1 && qldOutlets[0].UserId != userId {
						return int64(qldOutlets[0].Type), 2, 0, 0, status, priceDes, errMsg, nil
					} else {
						return int64(qldOutlets[0].Type), 0, 0, 0, status, priceDes, errMsg, nil
					}
					//}
				}
			}
		}
	}
}

func getDevType(snNum string) (int64, error) {
	if tmp, ok := devMap.Get(snNum); !ok {
		return -1, nil
	} else {
		if devTypeStr, ok := tmp.(string); !ok {
			errNew := utils.NewError(utils.ErrorTypeStop, "getDevType:设备类型字符串数据转换失败，"+snNum)
			utils.MyPrint(utils.PRINT_ERROR, errNew.Msg())
			return 0, errNew
		} else if devType, err := strconv.ParseInt(devTypeStr, 10, 64); err != nil {
			errNew := utils.NewError(utils.ErrorTypeStop, "getDevType:设备类型整型数据转换失败，"+snNum)
			utils.MyPrint(utils.PRINT_ERROR, errNew.Msg())
			return 0, errNew
		} else {
			return devType, nil
		}
	}
}

type DevStatus struct {
	snNum  string
	status int8
}

func makeDevStatusQueue() {
	recvDevStatusChan = make(chan DevStatus, DEV_STATUS_QUEUE_LENGTH)
	go setDevStatusChange()
}
func setDevStatusChange() {
	for {
		devStatus := <-recvDevStatusChan
		time.Sleep(time.Second * 10)
		chanLen := len(recvDevStatusChan) + 1
		if chanLen > 10000 {
			chanLen = 10000
		}
		devSnNumList := make([]DevStatus, chanLen)
		devSnNumList[0] = devStatus
		onlineNum := 0
		offlineNum := 0
		if devStatus.status == 0 {
			onlineNum++
		} else if devStatus.status == 2 {
			offlineNum++
		}
		for i := 1; i < chanLen; i++ {
			devSnNumList[i] = <-recvDevStatusChan
			if devSnNumList[i].status == 0 {
				onlineNum++
			} else if devSnNumList[i].status == 2 {
				offlineNum++
			}
		}
		devSnNumOnlineListIndex := 0
		devSnNumOnlineList := make([]string, onlineNum)
		devSnNumOfflineListIndex := 0
		devSnNumOfflineList := make([]string, offlineNum)
		for i := 0; i < chanLen; i++ {
			if devSnNumList[i].status == 0 {
				devSnNumOnlineList[devSnNumOnlineListIndex] = devSnNumList[i].snNum
				devSnNumOnlineListIndex++
			} else if devSnNumList[i].status == 2 {
				devSnNumOfflineList[devSnNumOfflineListIndex] = devSnNumList[i].snNum
				devSnNumOfflineListIndex++
			}
		}
		if onlineNum > 0 {
			utils.MyPrint(utils.PRINT_WARN, "setDevStatusChange", devSnNumOnlineList)
			err := models.SetQldOutleStatusBySnNumList(devSnNumOnlineList, 0)
			if err != nil {
				newErr := utils.WrapError(err, "setDevStatusChange:数据库设备上线信息更新失败")
				utils.MyPrint(utils.PRINT_ERROR, newErr.Error())
			}
		}
		if offlineNum > 0 {
			utils.MyPrint(utils.PRINT_WARN, "setDevStatusChange", devSnNumOfflineList)
			err := models.SetQldOutleStatusBySnNumList(devSnNumOfflineList, 2)
			if err != nil {
				newErr := utils.WrapError(err, "setDevStatusChange:数据库设备离线信息更新失败")
				utils.MyPrint(utils.PRINT_ERROR, newErr.Error())
			}
		}
	}
}
func PutDevStatusChange(snNum string, status int8) {
	if len(recvDevStatusChan) > DEV_STATUS_QUEUE_LENGTH {
		utils.MyPrint(utils.PRINT_WARN, "recvDevStatusChan is full", snNum, status)
	} else {
		utils.MyPrint(utils.PRINT_WARN, len(recvDevStatusChan), snNum, "status will be", status)
		recvDevStatusChan <- DevStatus{snNum: snNum, status: status}
	}
}

func SaveUserIdAndSnNum(userId int64, snNum string) error {
	if snNumKeyListStr, err2 := RedisGet("userId_snNum/"+strconv.FormatInt(userId, 10), ""); err2 != nil {
		return utils.WrapError(err2, "GetQldOutletChargeInfo:读取redis数据失败")
	} else {
		result := strings.Split(snNumKeyListStr, ",")
		for i := 0; i < len(result); i++ {
			if result[i] == snNum {
				return nil
			}
		}
		if len(snNumKeyListStr) > 0 {
			snNumKeyListStr += ","
		}
		snNumKeyListStr += snNum
		if err := RedisSave("userId_snNum/"+strconv.FormatInt(userId, 10), snNumKeyListStr); err != nil {
			return utils.WrapError(err, "OutLetOpen: 10，userId_snNum保存到redis失败")
		}
	}
	return nil
}

func DelUserIdAndSnNum(userId int64, snNum string) error {
	if snNumKeyListStr, err2 := RedisGetNoHeader("/qld2devservice/userId_snNum/"+strconv.FormatInt(userId, 10), ""); err2 != nil {
		return utils.WrapError(err2, "GetQldOutletChargeInfo:读取redis数据失败")
	} else {
		snNumKeyListStrNew := ""
		result := strings.Split(snNumKeyListStr, ",")
		for i := 0; i < len(result); i++ {
			if result[i] == snNum || len(result[i]) == 0 {
				continue
			}
			if isWorking, err2 := RedisGetNoHeader("/qld2devservice/"+result[i]+"/isWorking", "0"); err2 != nil {
				utils.MyPrint(utils.PRINT_ERROR, err2.Error())
				return utils.WrapError(err2, "GetQldOutletChargeInfo:读取redis数据失败")
			} else if isWorking == "1" {
				if len(snNumKeyListStrNew) > 0 {
					snNumKeyListStrNew += ","
				}
				snNumKeyListStrNew += result[i]
			}
		}
		if err := RedisSaveNoHeader("/qld2devservice/userId_snNum/"+strconv.FormatInt(userId, 10), snNumKeyListStrNew); err != nil {
			return utils.WrapError(err, "OutLetOpen: 10，userId_snNum保存到redis失败")
		}
	}
	return nil
}

func CheckEmergencyStop(snNum string, devType int8) (alarmMsg string) {
	if devType == 0 || devType == 2 {
		if state, err2 := RedisGet(snNum+"/state", "0000000"); err2 != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err2, "CheckEmergencyStop:etcd设备state获取失败").Error())
		} else if state[0] == '0' && state[1] == '2' {
			alarmMsg = "急停按钮已被按下，请您手动松开右侧的急停按钮"
		}
	}
	var err2 error
	if devType == 6 {
		if alarmMsg, err2 = RedisGet(snNum+"/ganAlarmInfo", ""); err2 != nil {
			utils.MyPrint(utils.PRINT_ERROR, utils.WrapError(err2, "CheckEmergencyStop:大直流告警信息获取失败").Error())
		}
	}
	return
}
